/*
        Author: Nathan Newman
        File Name: commhand.c
        Description: Front end user interface functionality that interfaces with command line commands
        Last updated: 9/12/11

*/


/*
REFERENCE:
	int sys_req  ( int op_code,	    {READ,WRITE,CLEAR,GOTOXY,IDLE,EXIT}
			       int device_id,	{TERMINAL, COM_PORT}
			       char *buf_p,		{the from/to buffer}
			       int *count_p		{length of buffer}
		      );

*/

#include "mpx_supt.h"
#include "commhand.h"
#include "dir.h"
#include "version.h"
#include "date.h"
#include "help.h"
#include "pcbCom.h"
#include "r3code.h"
#include "r4code.h"

/* Welcomes user, gets command line arguments, and passes them to functions for interpretation */
void comhan(){
	int foundCom = FALSE,buffsize=MAX_LINE,numArgs,i,comStat,readStat;
	char next[MAX_LINE];
	char words[MAX_NARGS][MAX_ARGLEN]; //hold array of strings of input
	command commands[N_COMMANDS] = 
	{
		{&getDir},
		{&getVersion},
		{&getDate},
		{&getHelp},
		{&getPcbCommand},
		{&loadr3_command},
		{&dispatch_command},
		{&load_command},
		{&terminate_pcb_command}
		//TODO: {&getExec}
	};
	
	//sys_req(CLEAR,TERMINAL,next,&buffsize);
	
	printf(
"\n\n\n"	
"MMMMMMMM               MMMMMMMMPPPPPPPPPPPPPPPPP   XXXXXXX       XXXXXXX\n"
"M:::::::M             M:::::::MP::::::::::::::::P  X:::::X       X:::::X\n"
"M::::::::M           M::::::::MP::::::PPPPPP:::::P X:::::X       X:::::X\n"
"M:::::::::M         M:::::::::MPP:::::P     P:::::PX::::::X     X::::::X\n"
"M::::::::::M       M::::::::::M  P::::P     P:::::PXXX:::::X   X:::::XXX\n"
"M:::::::::::M     M:::::::::::M  P::::P     P:::::P   X:::::X X:::::X   \n"
"M:::::::M::::M   M::::M:::::::M  P::::PPPPPP:::::P     X:::::X:::::X    \n"
"M::::::M M::::M M::::M M::::::M  P:::::::::::::PP       X:::::::::X     \n"
"M::::::M  M::::M::::M  M::::::M  P::::PPPPPPPPP         X:::::::::X     \n"
"M::::::M   M:::::::M   M::::::M  P::::P                X:::::X:::::X    \n"
"M::::::M    M:::::M    M::::::M  P::::P               X:::::X X:::::X   \n"
"M::::::M     MMMMM     M::::::M  P::::P            XXX:::::X   X:::::XXX\n"
"M::::::M               M::::::MPP::::::PP          X::::::X     X::::::X\n"
"M::::::M               M::::::MP::::::::P          X:::::X       X:::::X\n"
"M::::::M               M::::::MP::::::::P          X:::::X       X:::::X\n"
"MMMMMMMM               MMMMMMMMPPPPPPPPPP          XXXXXXX       XXXXXXX\n"

"			 ______     ___   	 \n"	
"			/\\__  _\\  /'___`\\   \n"
"Brought to you by	\\/_/\\ \\/ /\\_\\ /\\ \\  \n"
"			   \\ \\ \\ \\/_/// /__   \n"
"			    \\_\\ \\__ // /_\\ \\ \n"
"			    /\\_____\\\\______/ \n"
"			    \\/_____//_____/  \n"
			
	
			"\nHello and welcome! "
			"Type in a command, and I will blow your mind...\n"
		);
		
	//end_all_processes();	
	//sys_req(EXIT, NO_DEV, NULL, 0);
	//return;
	
	
	while(TRUE){
		printf("> ");
		buffsize = MAX_LINE;
		if(sys_req(READ,TERMINAL,next,&buffsize) == ERR_SUP_RDFAIL){
			printf("Knock it off, wise guy! I can't read that.\n");
			continue;
		}
		//check for extra long overflow into stdin
		//if(strlen(next) == (MAX_LINE-1) && next[MAX_LINE-2]!='\n') {
		if(inputBufOv(next)){
			clearStdinJunk();
			printf("Knock it off, wise guy!\n");
			continue;
		}
		numArgs = split(words,next);
		if(numArgs==0) continue;
		if(strcmp(words[0],"EXIT")==0||strcmp(words[0],"QUIT")==0){
			if(confirmExit()==0) break;
			else continue;
		}
		for(i=0 ; i<N_COMMANDS ; i++){
			comStat = (*commands[i].fxn) (words,numArgs);
			if(comStat==1){
				foundCom=TRUE;
				break;
			}	
		}
		if(foundCom==FALSE) printf("Unrecognized command: %sFor a list of acceptable commands, type HELP\n",next);
		foundCom=FALSE;
	}
	//get rid of any remaining processes -- comhan is the BOSS
	end_all_processes();
	sys_req(EXIT, NO_DEV, NULL, 0);
}

/* Function for testing purposes only */
int dummyCommand(char args[MAX_NARGS][MAX_ARGLEN], int nArgs){
	int i;
	printf("This is a dummy command\n");
	for(i=0; i<nArgs; i++){
		printf("Argument %d is %s\n",i,args[i]);
	}
	return 1;
}

/* function that splits the string *toSplit into upper case command line arguments by using blank space as the delimiter */
int split(char strArray[MAX_NARGS][MAX_ARGLEN], char *toSplit){
	int i=0,j=0,len = strlen(toSplit),numWords = 0;
	char c=toSplit[i];
	while(c==' '){ //disregard initial white space
		c=toSplit[++i];
	}
	if(c=='\n') return 0; //no meaningful arguments
	while(i < len){
		if(numWords >= MAX_NARGS || j >= MAX_ARGLEN) {
			printf("Error: invalid input.\nAt most %d arguments can be provided, and\neach argument cannot be more than %d characters.\n",MAX_NARGS,MAX_ARGLEN);
			return 0;
		}
		c = toSplit[i];
		if(c=='\n'){ //end of line in command prompt is always '\n'
			strArray[numWords++][j]='\0';
			return numWords;
		}
		else if(c==' '){ //first space indicates end of word; skip subsequent spaces
			strArray[numWords++][j]='\0';
			j = -1; //reset to start index (after next increment) for next string
			c = toSplit[i+1]; //look ahead one index, increment so that i+1 is non-space (and later increment one more time) 
			while(c==' '){
				c = toSplit[(++i)+1];
			}
			if(c=='\n') return numWords;
		}
		else { //copy character into appropriate location
			strArray[numWords][j] = toupper(c);
		}
		i++;
		j++;
	}
	return numWords;
}

/* Confirms user wants to exit the program
	Return 0 for normal exit or -1 to return to program */
int confirmExit(){
	char buf[4];
	int bufSize = 4, count=0;
	printf("Are you sure you want to Quit? (Y/N) ");
	while(count++ < 5){
		sys_req(READ,TERMINAL,buf,&bufSize);
		if(strlen(buf)==2) {
			switch (buf[0]) {
				case 'y': printf("I've enjoyed our time together.  Goodbye\n"); return 0;
				case 'Y': printf("I've enjoyed our time together.  Goodbye\n"); return 0;
				case 'n': printf("Welcome back!\n"); return -1;
				case 'N': printf("Welcome back!\n"); return -1;
				default: ;//Keep reading until we get sick of this
			}	
		}
		else if( buf[2]!='\n' ) clearStdinJunk(); 
		printf("Type Y to quit or N to return to the program: ");		
	}
	printf("\nI'm sick of this nonsense.  Goodbye.\n");
	return 0;
}

/* Prompt user to continue displaying multi-page output
	Return 0 to continue display as usual, or -1 to halt display */
int pager(int* lineCntPtr,int inc){
	int nextLineCnt = ((*lineCntPtr)+inc);
	char buf[2];
	int bufSize = 2;
	if(nextLineCnt >= MAX_LINES_PER_PAGE){
		(*lineCntPtr) = 0;
		printf("Enter Q to stop output display or anything else to continue display:  "); 
		sys_req(READ,TERMINAL,buf,&bufSize);
		if(inputBufOv(buf)) clearStdinJunk();
		printf("\n");
		if(buf[0]=='q' || buf[0]=='Q') return -1;
	}
	else (*lineCntPtr) = nextLineCnt;	
	return 0;
}

/* remove data in the stdin buffer that holds excess user input
	that hasn't been completely captured by the character string buffer used
	by sys_req */
void clearStdinJunk(){
	int size = 2;
	char next[3] = "GO";
	while( strcmp(next,"\n") != 0) sys_req(READ,TERMINAL,next,&size);
		
}

/* Detects whether the given string has indeed captured all of the user input
	from stdin. Return 0 if not true, nonzero if true.  */
int inputBufOv(char* buf){
	int len = strlen(buf);
	return (len>=MAX_LINE && buf[len-1] != '\n');
}
